package cn.itsource.set.treeset;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * 集合框架：
	Iterable（迭代器接口，实现了该接口可以使用foreach,还可以获取集合对象的迭代器对象，通过迭代器遍历集合） 
		|
		|---iterator() =======>Iterator
		|					  		|	
		|	listIterator()获取	ListIterator
		|
 * 	Collection(所有集合的根接口)  
 * 		|----List(接口)表示有序（存入和取出）可重复集合，可以保存null元素 
 * 				|---ArrayList(实现类) 基于数组，查改快  
 * 				|---LinkedList(实现类)基于变量，增删快 
 * 				|	因为LinkedList中有多个接口的实现方法，所以，同样一个功能可以有多个方法实现，
 * 					但是，尽量不要交叉使用（使用同一个接口中的方法），因为交叉使用就会导致
 *					既不能完全具其中有一个接口的完整特性
 * 				|---Vector(就是一个线程安全的ArrayList) 
 * 
 * 		|----Set(接口)表示无序（存入和取出）不可重复集合，可以保存null元素
 * 				|----HashSet(实现类)：基于HashMap，HashMap基于HashCode，是一个非线程安全。
 * 						HashMap：底层是一个键值对的数组，而键值对中存放数据的时候，通过链表或者红黑树存放
 * 						判断重复的机制：
 * 							1. 先判断元素的hashCode值
 * 							2. 在hashCode相等的情况下，继续判断equals比较，如果都相等认为是同一个元素
 * 							要判断是什么类型的对象是否为相同元素，就要比较该元素的数据类型中的hashCode和equals方法
 * 
 * 
 * 				|----TreeSet(实现类)：基于TreeMap，TreeMap底层基于红黑树（特殊的二叉树，左边叉值小，右边叉值大）
 * 				|		1. 自然排序：通过无参构造创建TreeSet对象，元素类型必须实现了Comparable接口，且必须重写compareTo（）方法
							返回值  正数：升序
						           返回值 负数：降序
							返回值0：相同的元素
							
						2. 定制排序：
 * 							在创建TreeSet对象的时候，传入一个Comparator接口的实现类，该实现类必须重写compare方法
 * 							返回值  正数：升序
						           返回值  负数：降序
							返回值 0：相同的元素
 * 					当自然排序和定制排序同时使用，定制排序优先级更高
 * 					一般会配合使用，默认排序使用自然排序，特定排序用定制排序
 * 				|
 * 				|----LinkedHashSet(是一个有序的HashSet，在HashSet基础上维护了一个链表) 
 * 
 * 		|-----Queue队列 
 * 				|---Deque双端队列
 * 			 	|---Stack栈
 * 
 * 
 * 	集合遍历方式：		只有List才有双向迭代器
 * 
 *		1. foreach()因为ArrayList间接实现了Iterable接口
 *		2. 迭代器：一个集合对象可以获取多个迭代器对象（多次调用方法）,指针都是在初始位置（第一个元素前面）
 *			Iterator<E> iterator()  单向迭代器
 *				1. boolean hasNext() 如果迭代具有更多元素，则返回 true 。  
				2. Object next() 返回迭代中的下一个元素。  
				3. default void remove() 从底层集合中删除此迭代器返回的最后一个元素（可选操作）。 
			
			ListIterator<E> listIterator() 双向迭代器
				void add(E e) 
					将指定的元素插入列表（可选操作）。  
				boolean hasNext() 
					返回 true如果遍历正向列表，列表迭代器有多个元素。  
				boolean hasPrevious() 
					返回 true如果遍历反向列表，列表迭代器有多个元素。  
				E next() 
					返回列表中的下一个元素，并且前进光标位置。  
				int nextIndex() 
					返回随后调用 next()返回的元素的索引。  
				E previous() 
					返回列表中的上一个元素，并向后移动光标位置。  
				int previousIndex() 
					返回由后续调用 previous()返回的元素的索引。  
				void remove() 
					从列表中删除由 next()或 previous()返回的最后一个元素（可选操作）。  
				void set(E e) 
					用 指定的元素替换由 next()或 previous()返回的最后一个元素（可选操作）。  

 *		3.遍历集合方式3：通过普通for循环，利用集合size()方法和get(int index)	（不常用）
 *
 * 		注意：在使用迭代器遍历集合的时候，不能使用集合自己的方法（增删改）操作集合对象
 * 
 * 
 * 	List和Set使用选择：
 * 		1. 如果是有序的使用List，如果增删多用LinkedList，查改多用ArrayList
 * 			如果有线程安全需求，用Vector
 * 		2. 如果是无序的使用Set，一般使用HashSet，因为效率高。
 * 			如果有排序需求，用TreeSet
 * 			如果有存入和取出顺序要求，用LinkedHashSet
 * 
 */
public class TreeSetTest2 {

	public static void main(String[] args) {
		/*
		 * 构造方法：
		 * 		TreeSet() 构造一个新的，空的树组，根据其元素的自然排序进行排序。  
				TreeSet(Collection c) 构造一个包含指定集合中的元素的新树集，根据其元素的 自然排序进行排序 。  
				TreeSet(Comparator comparator) 构造一个新的，空的树集，根据指定的比较器进行排序。  
					可以使用Comparator的实现类对象
					也可以使用Comparator的匿名内部类
					
		 */
		//创建一个User类型元素的比较器对象
		UserComparator comparator = new UserComparator();
		//将对象传入TreeSet构造方法中，定制排序
//		TreeSet set = new TreeSet(comparator);
		
		//使用匿名内部类方式：
		TreeSet set = new TreeSet(new Comparator<User>() {

			@Override
			public int compare(User o1, User o2) {
				return 0;//自己写业务判断
			}
		});
		System.out.println("=============添加自定义类型===========");
		
		//测试判断TreeSet判断重复的机制:定制排序 
		//自然排序：使用无参构造创建TreeSet对象，要添加的元素必须实现Comparable接口，重写compareTo()方法 
		//需求：学生类，姓名长度升序，如果姓名长度相同，再根据身高升序排序，如果姓名长度和身高长度都相等，则认为同一个元素		主要看：compareTo方法返回值
		set.clear();
		User stu1 = new User("苍苍",160);
		User stu2 = new User("苍苍",160);
		User stu8 = new User("翔翔",160);
		User stu3 = new User("翔翔有点短",170);
		User stu4 = new User("翔翔有点短",169);
		
		User stu5 = new User("张某民有点小",196);
		User stu6 = new User("张某民有点小很小",196);
		User stu7 = new User("张某民有点小是很小非常小",169);
		
		set.add(stu1);
		set.add(stu2);//因为根据元素的姓名长度和身高比较判断是否重复，所以不会添加该元素，因为前面有stu1苍苍了
		set.add(stu3);
		set.add(stu4);
		set.add(stu5);
		set.add(stu6);
		set.add(stu7);
		set.add(stu8);//因为根据元素的姓名长度和身高比较判断是否重复，所以不会添加该元素，因为前面有stu1苍苍了
		System.out.println(set);
		
	}

}

class User implements Comparable<User>{
	private String name;
	private double height;
	public User() {
	}
	public User(String name, double height) {
		super();
		this.name = name;
		this.height = height;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getHeight() {
		return height;
	}
	public void setHeight(double height) {
		this.height = height;
	}
	@Override
	public String toString() {
		return "[" + name + ", " + height + "]";
	}
	@Override
	public int compareTo(User o) {
		//需求：学生类，姓名长度升序，如果姓名长度相同，再根据身高升序排序，如果姓名长度和身高长度都相等，则认为同一个元素	
		if (this.name.length() > o.name.length()) {
			return 1;//正数表示升序
		} else if (this.name.length() < o.name.length()){
			return -1;//负数表示降序
		} else {//表示姓名长度相等才会进else
			if (this.height > o.height) { //姓名长度相等,按身高升序
				return 1;//正数表示升序
			} else if (this.height < o.height){//姓名长度相等,按身高降序
				return -1;//负数表示降序
			} else {//表示姓名长度相等且身高也相等才会进else
				return 0;//表示相同的元素
			}
		}
	}
	
}
